"""
提示词相关数据模型
包含提示词模板、参数定义等
"""
from sqlalchemy import Column, Integer, String, Text, Boolean, ForeignKey, DateTime, JSON
from sqlalchemy.orm import relationship
from sqlalchemy.sql import func
from typing import List, Optional, Any
import enum
from models.base import Base


class ParameterType(str, enum.Enum):
    """参数类型枚举"""
    STRING = "string"        # 字符串
    INTEGER = "integer"      # 整数
    FLOAT = "float"         # 浮点数
    BOOLEAN = "boolean"     # 布尔值
    ARRAY = "array"         # 数组
    OBJECT = "object"       # 对象
    DATE = "date"           # 日期
    DATETIME = "datetime"   # 日期时间


class OutputFormat(str, enum.Enum):
    """输出格式枚举"""
    JSON = "json"           # JSON格式
    TEXT = "text"          # 纯文本
    MARKDOWN = "markdown"  # Markdown格式
    HTML = "html"          # HTML格式
    XML = "xml"           # XML格式


class PromptTemplate(Base):
    """提示词模板模型"""
    
    __tablename__ = "prompt_templates"

    id = Column(Integer, primary_key=True)
    # 基本信息字段
    name = Column(String(100), nullable=False, comment="提示词名称")
    description = Column(Text, comment="提示词描述")
    content = Column(Text, nullable=False, comment="提示词内容")
    version = Column(String(20), default="1.0", comment="提示词版本")
    category = Column(String(50), comment="提示词分类")
    tags = Column(JSON, comment="标签列表")
    
    # 关联和配置字段
    service_type = Column(String(50), comment="关联的服务类型")
    service_id = Column(String(50), comment="关联的服务ID")
    is_active = Column(Boolean, default=True, comment="是否激活")
    is_system = Column(Boolean, default=False, comment="是否系统模板")
    
    # 输出配置
    output_format = Column(String(20), default=OutputFormat.JSON, comment="输出格式")
    output_schema = Column(JSON, comment="输出格式定义")
    expected_output = Column(Text, comment="期望输出示例")
    
    # 深度思考配置
    enable_thinking = Column(Boolean, default=False, comment="是否启用深度思考")
    
    # 使用统计
    usage_count = Column(Integer, default=0, comment="使用次数")
    last_used_at = Column(DateTime, comment="最后使用时间")
    
    # 关联参数定义
    parameters = relationship("PromptParameter", back_populates="template", cascade="all, delete-orphan")
    
    # 关联使用记录
    usage_records = relationship("PromptUsageRecord", back_populates="template")
    
    def to_dict(self) -> dict:
        """转换为字典"""
        result = super().to_dict()
        # 添加参数列表
        result['parameters'] = [param.to_dict() for param in self.parameters]
        return result
    
    def render(self, **kwargs) -> str:
        """渲染提示词内容"""
        rendered_content = self.content
        
        # 替换参数
        for param in self.parameters:
            param_name = param.name
            param_value = kwargs.get(param_name, param.default_value)
            
            # 创建占位符
            placeholder = f"{{{param_name}}}"
            
            # 根据参数类型处理值
            if param_value is not None:
                if param.param_type == ParameterType.ARRAY:
                    param_value = self._format_array_param(param_value)
                elif param.param_type == ParameterType.OBJECT:
                    param_value = self._format_object_param(param_value)
                elif param.param_type == ParameterType.BOOLEAN:
                    param_value = str(param_value).lower()
                else:
                    param_value = str(param_value)
            else:
                param_value = ""
            
            # 替换占位符
            rendered_content = rendered_content.replace(placeholder, param_value)
        
        return rendered_content
    
    def _format_array_param(self, value: List[Any]) -> str:
        """格式化数组参数"""
        if isinstance(value, list):
            return ", ".join(str(item) for item in value)
        return str(value)
    
    def _format_object_param(self, value: dict) -> str:
        """格式化对象参数"""
        if isinstance(value, dict):
            return "\n".join(f"{k}: {v}" for k, v in value.items())
        return str(value)
    
    def validate_parameters(self, **kwargs) -> List[str]:
        """验证参数"""
        errors = []
        
        for param in self.parameters:
            param_name = param.name
            param_value = kwargs.get(param_name)
            
            # 检查必填参数
            if param.is_required and param_value is None:
                errors.append(f"参数 '{param_name}' 是必填的")
                continue
            
            # 检查参数类型
            if param_value is not None:
                if not self._validate_param_type(param_value, param.param_type):
                    errors.append(f"参数 '{param_name}' 类型错误，期望 {param.param_type.value}")
                
                # 检查枚举值
                if param.enum_values and param_value not in param.enum_values:
                    errors.append(f"参数 '{param_name}' 值无效，有效值: {param.enum_values}")
        
        return errors
    
    def _validate_param_type(self, value: Any, param_type: ParameterType) -> bool:
        """验证参数类型"""
        try:
            if param_type == ParameterType.STRING:
                return isinstance(value, str)
            elif param_type == ParameterType.INTEGER:
                return isinstance(value, int)
            elif param_type == ParameterType.FLOAT:
                return isinstance(value, (int, float))
            elif param_type == ParameterType.BOOLEAN:
                return isinstance(value, bool)
            elif param_type == ParameterType.ARRAY:
                return isinstance(value, list)
            elif param_type == ParameterType.OBJECT:
                return isinstance(value, dict)
            elif param_type == ParameterType.DATE:
                from datetime import date
                return isinstance(value, (date, str))
            elif param_type == ParameterType.DATETIME:
                from datetime import datetime
                return isinstance(value, (datetime, str))
            return True
        except:
            return False


class PromptParameter(Base):
    """提示词参数模型"""
    
    __tablename__ = "prompt_parameters"
    
    # 外键关联
    template_id = Column(Integer, ForeignKey("prompt_templates.id"), nullable=False, comment="关联的提示词模板ID")
    
    # 基本信息字段
    name = Column(String(50), nullable=False, comment="参数名称")
    description = Column(Text, comment="参数描述")
    param_type = Column(String(20), default=ParameterType.STRING, comment="参数类型")
    field_path = Column(String(200), comment="数据字段路径")
    
    # 验证规则
    is_required = Column(Boolean, default=False, comment="是否必填")
    default_value = Column(String(500), comment="默认值")
    enum_values = Column(JSON, comment="枚举值列表")
    min_length = Column(Integer, comment="最小长度")
    max_length = Column(Integer, comment="最大长度")
    min_value = Column(Integer, comment="最小值")
    max_value = Column(Integer, comment="最大值")
    pattern = Column(String(200), comment="正则表达式模式")
    
    # UI配置
    display_name = Column(String(100), comment="显示名称")
    placeholder = Column(String(200), comment="占位符文本")
    help_text = Column(Text, comment="帮助文本")
    ui_component = Column(String(50), default="input", comment="UI组件类型")
    
    # 深度思考配置
    enable_thinking = Column(Boolean, default=False, comment="是否在深度思考中使用此参数")
    
    # 排序
    sort_order = Column(Integer, default=0, comment="排序顺序")
    
    # 关联
    template = relationship("PromptTemplate", back_populates="parameters")
    
    def to_dict(self) -> dict:
        """转换为字典"""
        result = super().to_dict()
        # 转换枚举值为字符串
        if self.enum_values:
            result['enum_values'] = list(self.enum_values)
        return result


class PromptUsageRecord(Base):
    """提示词使用记录模型"""
    
    __tablename__ = "prompt_usage_records"
    
    # 外键关联
    id = Column(Integer, primary_key=True, comment="记录ID")
    template_id = Column(Integer, ForeignKey("prompt_templates.id"), nullable=False, comment="提示词模板ID")
    user_id = Column(Integer, ForeignKey("user.id"), comment="用户ID")
    
    # 使用信息
    input_data = Column(JSON, comment="输入数据")
    rendered_prompt = Column(Text, comment="渲染后的提示词")
    output_data = Column(JSON, comment="输出数据")
    execution_time = Column(Integer, comment="执行时间(毫秒)")
    token_count = Column(Integer, comment="使用的token数量")
    cost = Column(String(50), comment="费用")
    
    # 结果信息
    status = Column(String(20), default="success", comment="执行状态")
    error_message = Column(Text, comment="错误信息")
    
    # 关联
    template = relationship("PromptTemplate", back_populates="usage_records")
    
    def to_dict(self) -> dict:
        """转换为字典"""
        result = super().to_dict()
        # 过滤敏感信息
        if 'input_data' in result:
            result['input_data_preview'] = str(result['input_data'])[:100] + "..." if len(str(result['input_data'])) > 100 else str(result['input_data'])
        return result


class PromptCategory(Base):
    """提示词分类模型"""
    
    __tablename__ = "prompt_categories"
    
    # 基本信息字段
    id = Column(Integer, primary_key=True, comment="分类ID")
    name = Column(String(50), nullable=False, unique=True, comment="分类名称")
    description = Column(Text, comment="分类描述")
    parent_id = Column(Integer, ForeignKey("prompt_categories.id"), comment="父分类ID")
    sort_order = Column(Integer, default=0, comment="排序顺序")
    is_active = Column(Boolean, default=True, comment="是否激活")
    
    # 统计信息
    template_count = Column(Integer, default=0, comment="模板数量")
    
    # 自关联关系
    children = relationship("PromptCategory", remote_side=[id])
    parent = relationship("PromptCategory", remote_side=[parent_id])
    
    def to_dict(self) -> dict:
        """转换为字典"""
        result = super().to_dict()
        # 添加子分类
        result['children'] = [child.to_dict() for child in self.children]
        return result


class PromptTemplateVersion(Base):
    """提示词模板版本模型"""
    
    __tablename__ = "prompt_template_versions"
    
    # 外键关联
    template_id = Column(Integer, ForeignKey("prompt_templates.id"), nullable=False, comment="提示词模板ID")
    user_id = Column(Integer, ForeignKey("user.id"), comment="创建用户ID")
    
    # 版本信息
    version = Column(String(20), nullable=False, comment="版本号")
    content = Column(Text, nullable=False, comment="版本内容")
    changelog = Column(Text, comment="变更日志")
    
    # 版本状态
    is_active = Column(Boolean, default=False, comment="是否当前激活版本")
    is_published = Column(Boolean, default=False, comment="是否已发布")
    
    # 关联
    template = relationship("PromptTemplate")
    
    def to_dict(self) -> dict:
        """转换为字典"""
        return super().to_dict()